package com.veetao.api.controller;

import com.veetao.api.utils.HttpUtil;
import com.veetao.api.utils.JsonFormatUtil;
import com.veetao.api.utils.McpUtils;
import org.apache.commons.codec.CharEncoding;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 测试用
 *
 * @author Marshall
 */
@Controller
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
public class TestController extends AbstractController implements InitializingBean {
    private static final Log logger = LogFactory.getLog(TestController.class);
    @Autowired
    private CloseableHttpClient client;
    private static final String[] allowdIps = {"127.0.0.1", "0:0:0:0:0:0:0:1", "192.168.", "106.38.92.46"};

    @Autowired(required = false)
    private TestEnvHolder envHolder;

    private static boolean isIpAllowed(String fromIp) {
        for (String ip : allowdIps) {
            if (fromIp.startsWith(ip)) {
                return true;
            }
        }
        return false;
    }

    @RequestMapping("/test")
    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String result = null;
        try {
            final String ip = request.getRemoteAddr();
            if (needCheckIP(request) && !isIpAllowed(ip)) {
                result = "access denied! " + ip;
                return null;
            }
            final int appId = NumberUtils.toInt(request.getParameter("_i"));// appId
            if (appId < 1) {
                result = buildResp(0, "", "", "", "请用_i指定appId参数。");
                return null;
            }
            String secretKey = request.getParameter("_s");// appId对应的secretkey
            if (secretKey == null || secretKey.isEmpty()) {
                result = buildResp(0, "", "", "", "请用_s指定appId对应的secretKey参数。");
                return null;
            }
            if ("GET".equalsIgnoreCase(request.getMethod())) {// 返回基本页面
                result = buildResp(0, "", "", "", "");
                return null;
            }
            // 请求并得到结果
            final String userSecretKey = request.getParameter("_u");// 用户t票对应的secretKey
            if (userSecretKey != null && userSecretKey.length() > 0) {
                secretKey = secretKey + userSecretKey;
            }
            final String parames = request.getParameter("_p");// 用户t票对应的secretKey
            final int envId = NumberUtils.toInt(request.getParameter("_e"));// 环境编号
            if (envId < 0 || envId >= envs.size()) {
                result = buildResp(0, "", "", "", "请不要伪造环境参数。");
                return null;
            }
            final String method = request.getParameter("_m");// 接口名称
            if (method == null || method.isEmpty()) {
                result = buildResp(envId, method, parames, "请指定要测试的接口名称。", "");
                return null;
            }
            // 取请求参数，增加默认参数
            final Map<String, String> reqMap = new HashMap<String, String>();
            {
                reqMap.put("appId", String.valueOf(appId));
                reqMap.put("v", "1.0");
                if (parames != null && parames.length() > 0) {
                    String[] ps = parames.split("[\r\n]");
                    for (String p : ps) {
                        if (p.isEmpty())
                            continue;
                        String[] kv = p.split("[=]", 2);
                        if (kv.length != 2)
                            continue;
                        if (kv[0].equals("appId")) {
                            result = buildResp(envId, method, parames, "AppId已经在测试平台URL中指定，请不要重复提供。", "");
                            return null;
                        }
                        if (kv[0].equals("sig")) {
                            result = buildResp(envId, method, parames, "本测试平台会自动计算sig值，无需提供此参数。", "");
                            return null;
                        }
                        if (kv[0].equals("gz")) {
                            continue;
                        }
                        reqMap.put(kv[0], kv[1]);
                    }
                }
            }

            reqMap.put("callId", System.currentTimeMillis() + "");
            // 算sig值
            String normalizedString = McpUtils.generateNormalizedString(null, reqMap);
            String sig = McpUtils.generateSignature(normalizedString, secretKey);
            reqMap.put("sig", sig);
            final String body = HttpUtil.getPostBodyFromMap(reqMap);
            final String url = ((envs.get(envId).startsWith(ENV_TEST) && IP_LOCAL.startsWith("192.168.")) ? ENV_TEST_REAL : envs.get(envId)) + method.replaceAll("[.]", "/");
            try {
                String json = HttpUtil.postForm(client, url, body);
                if (json.startsWith("<")) {
                    json = json.replaceAll("<", "&lt;");
                    json = json.replaceAll(">", "&gt;");
                }
                logger.info(String.format("test %s,%s,%s,%s,%s,%s", request.getRemoteAddr(), appId, envId, method, parames, json));
                result = buildResp(envId, method, parames, json, "");
            } catch (Exception e) {
                result = buildResp(envId, method, parames, e.getMessage(), "");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (result == null) {
                return null;
            }
            response.setContentType("text/html");
            // 禁用页面缓存
            response.setHeader("Pragma", "no-cache");
            response.addHeader("Cache-Control", "must-revalidate");
            response.addHeader("Cache-Control", "no-cache");
            response.addHeader("Cache-Control", "no-store");
            response.addHeader("Content-Type", "text/html; charset=UTF-8");
            response.setDateHeader("Expires", 0);

            try (OutputStream os = response.getOutputStream()) {
                byte[] ob = result == null ? null : result.getBytes(CharEncoding.UTF_8);
                os.write(ob);
                os.flush();
            }
        }
        return null;

    }

    private boolean needCheckIP(HttpServletRequest request) {
        return !"n0".equals(request.getParameter("_chkIp"));
    }

    private static final String ENV_TEST = "http://localhost:9001/api/";
    private static final String ENV_TEST_REAL = "http://localhost:9001/api/";
    private static final String ENV_TEST_REAL_TANQIAN = "http://localhost:9006/api/";
    private static final String ENV_TEST_REAL_TANQIAN_PRE = "http://localhost:9011/api/";
    private static final String ENV_TEST_REAL_TANQIAN_RE = "http://api.tanqian.whenhi.cn/api/";
    private static final String ENV_TEST_REAL_TANQIAN_RE_PREPARE = "http://api.tanqian.whenhi.cn/v3/pre/";
    private static final String ENV_TEST_REAL_TANQIAN_RE_PREPARE_TASK = "http://api.tanqian.whenhi.cn/v3/preTask/";
    private static final String IP_LOCAL = McpUtils.getLocalIp();
    private List<String> envs;

    private String buildResp(int envId, String methodName, String ps, String resp, String error) {
        final StringBuilder sb = new StringBuilder();
        sb.append("<html><head><meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\"/><title>测试平台</title></head><body>");
        sb.append("<form method=\"POST\"><table style=\"border-spacing:0px;\">");
        boolean isError = false;
        if (error != null && error.length() > 0) {
            isError = true;
            sb.append(String.format("<caption><font color='red'><b><br/>%s</b></font></caption>", error));
        }
        sb.append("<tr><td colspan=\"2\">");
        sb.append("<b>目标环境：</b><select name=\"_e\">");
        for (int i = 0; i < envs.size(); i++) {
            if (i == envId) {
                sb.append(String.format("<option value=\"%s\" selected=\"selected\">%s</option>", i, envs.get(i)));
            } else {
                sb.append(String.format("<option value=\"%s\">%s</option>", i, envs.get(i)));
            }
        }
        sb.append("</select><br/><br/>");
        sb.append(String.format("<b>接口名称：</b><input name=\"_m\" value=\"%s\" /><br/>", methodName));
        sb.append(
                "</td></tr><tr><td width=\"700px\" style=\"border-right-width:1px;border-right-style:solid;\"><b>请求参数：</b>每行一个参数，格式为：key=value</td><td><b>返回结果</b><hr/></td></tr><tr>");
        sb.append("<td valign=\"top\" style=\"border-right-width:1px;border-right-style:solid;\">");
        sb.append(String.format("<textarea rows=\"20\" cols=\"80\" name=\"_p\" style=\"word-wrap:normal;\">%s</textarea><br/>", ps));
        if (isError) {
            sb.append("<font color='red'><b>请处理顶部提示的错误。</b></font>");//
        } else {
            sb.append("<input type=\"submit\" name=\"_skip\" value=\"提交\">");//
        }
        sb.append("</td><td valign=\"top\"><pre>");//
        if (resp != null && resp.length() > 0) {
            sb.append(JsonFormatUtil.formatJson(resp, "  "));
        }
        sb.append("</pre></td></tr></table></form></body></html>");
        return sb.toString();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.envs = new ArrayList<>();
        this.envs.add(ENV_TEST);
        this.envs.add(IP_LOCAL);
        this.envs.add(ENV_TEST_REAL_TANQIAN);
        this.envs.add(ENV_TEST_REAL_TANQIAN_PRE);
        this.envs.add(ENV_TEST_REAL_TANQIAN_RE);
        this.envs.add(ENV_TEST_REAL_TANQIAN_RE_PREPARE);
        this.envs.add(ENV_TEST_REAL_TANQIAN_RE_PREPARE_TASK);
        this.envs.add("http://localhost:9007/api/");
        if (envHolder != null) {
            String[] moreEnvs = envHolder.getEnvs();
            for (String e : moreEnvs) {
                envs.add(e);
            }
        }
    }

}
